using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using OpenComposite.Properties;

namespace OpenComposite.Base.Designer
{
	public class ListView : DesignerControl
	{
		#region Initialization
		public ListView()
		{
			init();
		}
		private void init()
		{
			this.BeginUpdate();

			this.AllowDrop = true;

			//this.Name = "listView" + GetCount(typeof(ListView));
			this.Text = this.Name;

			_penBorder = new Pen(Color.Gainsboro, 1);
			_penSelectedRow = new Pen(Color.CadetBlue, 1);
			_format = new StringFormat(StringFormat.GenericTypographic);
			_format.Trimming = StringTrimming.EllipsisCharacter;
			_format.LineAlignment = StringAlignment.Center;

			_bShowHeader = true;
			_brushHeaderFore = new SolidBrush(Color.DarkGoldenrod);
			_brushHeaderBack = new SolidBrush(Color.GhostWhite);

			_iFirst = 0;
			_iSelected = -1;
			_iRowHeight = 20;
			_iHeaderHeight = 20;
			_iScrollBtnHeight = 8;

			_rectUp = Rectangle.Empty;
			_rectDown = Rectangle.Empty;

			_columns = new ColumnCollection(this);
			_rows = new RowCollection(this);

			calculateScrollButtons();

			this.EndUpdate();
		}
		#endregion

		#region Public Members

		#region Properties

		public bool ShowHeader
		{
			get { return _bShowHeader; }
			set
			{
				bool changed = false;
				if ( _bShowHeader != value )
					changed = true;
				_bShowHeader = value;
				if ( changed )
					doShowHeaderChanged();
			}
		}

		public Color HeaderBackgroundColor
		{
			get { return _brushHeaderBack.Color; }
			set
			{
				_brushHeaderBack.Color = value;
				Repaint();
			}
		}
		public Color HeaderForeColor
		{
			get { return _brushHeaderFore.Color; }
			set
			{
				_brushHeaderFore.Color = value;
				Repaint();
			}
		}

		public ColumnCollection Columns
		{
			get { return _columns; }
		}
		public RowCollection Rows
		{
			get { return _rows; }
		}

		public int SelectedIndex
		{
			get { return _iSelected; }
			set
			{
				_iSelected = value;
				doSelectedIndexChanged();
			}
		}

		public Rectangle UpButtonRectangle
		{
			get { return _rectUp; }
		}
		public Rectangle DownButtonRectangle
		{
			get { return _rectDown; }
		}
		#endregion

		#region Events
		public event EventHandler<FieldMoveEventArgs> FieldMoved;
		#endregion

		#region Methods
		internal void RecalculateRowBounds(Row row, int pos, List<int> columnWidths)
		{
			Rectangle r, bounds;
			int x, y, w, h;
			h = _iRowHeight;
			x = 0;
			y = ( pos - _iFirst ) * _iRowHeight + _iScrollBtnHeight;
			bounds = Rectangle.Empty;
			if ( this.ShowHeader )
				y += _iHeaderHeight;
			for ( int i = 0; i < columnWidths.Count; i++ ) {
				w = columnWidths[i];
				string str = "";
				if ( row.Count > i && row[i] != null )
					str = row[i].ToString();
				r = RectangleToDesignerView(new Rectangle(x, y, w, h));
				row.SetColumnRectangle(i, r);
				r.Inflate(-2, -2);
				if ( bounds == Rectangle.Empty )
					bounds = r;
				else
					bounds = Rectangle.Union(bounds, r);
				x += w;
			}
			bounds.Inflate(1, 1);
			row.SetBounds(bounds);
		}
		internal List<int> CalculateColumnWidths()
		{
			int availableWidth = this.Width;
			int totalFill = 0;
			List<int> colWidths = new List<int>(this.Columns.Count);
			Dictionary<int, Column> dicFill = new Dictionary<int, Column>();

			// add absolute widths
			foreach ( Column col in this.Columns ) {
				if ( availableWidth >= col.Width ) {
					if ( col.Width == -1 ) {
						colWidths.Add(0);
						totalFill += col.FillWeight;
						dicFill.Add(colWidths.Count - 1, col);
					} else {
						colWidths.Add(col.Width);
						availableWidth -= col.Width;
					}
				} else {
					colWidths.Add(0);
				}
			}
			if ( availableWidth > 0 ) {
				// calulate relative widths
				foreach ( KeyValuePair<int, Column> kv in dicFill ) {
					int w = (int)( availableWidth * ( (double)kv.Value.FillWeight / (double)totalFill ) );
					colWidths[kv.Key] = w;
				}
			}
			return colWidths;
		}
		public Row GetRowAt(Point pt)
		{
			if ( _rows == null ) return null;
			foreach ( Row row in _rows ) {
				Rectangle bounds = row.Bounds;
				bounds.Inflate(1, 1);
				if ( bounds.Contains(pt) ) {
					return row;
				}
			}
			return null;
		}
		public Row GetRowAt(int x, int y)
		{
			return GetRowAt(new Point(x, y));
		}
		#endregion

		#region Overrides

		public override bool CanFocused
		{
			get
			{
				return true;
			}
		}
		public override bool CanSelect
		{
			get
			{
				return false;
			}
		}

		public override void Dispose()
		{
			dispose(_penBorder);
			dispose(_penSelectedRow);
			//dispose(_textBox);
			//dispose(_comboBox);

			base.Dispose();
		}
		public override void Paint(System.Windows.Forms.PaintEventArgs pe)
		{
			int pos;
			List<int> columnWidths = CalculateColumnWidths();
			Rectangle bounds = this.GetPaintBounds();
			Region clip = pe.Graphics.Clip;
			SmoothingMode sm = pe.Graphics.SmoothingMode;
			pe.Graphics.SmoothingMode = SmoothingMode.None;

			pe.Graphics.FillRectangle(this.BackBrush, bounds.X, bounds.Y, bounds.Width + 1, bounds.Height + 1);
			pe.Graphics.DrawRectangle(_penBorder, bounds);

			if ( this.ShowHeader )
				paintHeader(pe, columnWidths);

			paintScrollUpDown(pe);

			// clip list region
			pe.Graphics.Clip = new Region(
				new Rectangle(bounds.X,
							  bounds.Y + ( this.ShowHeader ? _iHeaderHeight : 0 ) + _iScrollBtnHeight,
							  bounds.Width,
							  bounds.Height - ( this.ShowHeader ? _iHeaderHeight : 0 ) - _iScrollBtnHeight * 2));

			// paint rows
			pos = 0;
			for ( int i = 0; i < this.Rows.Count; i++ ) {
				if ( i >= _iFirst ) {
					paintRow(pe, this.Rows[i], pos, columnWidths);
					pos++;
				} else {
					this.Rows[i].SetBounds(Rectangle.Empty);
				}
			}

			pe.Graphics.Clip = clip;
			pe.Graphics.SmoothingMode = sm;

			//if ( this.Status.DragObject is Row &&
			//     DesignerViewControl.MouseButtons == MouseButtons.Right ) {
			// check for row, because "IsDropAllowed" also checks parent
			if ( this.Status.DragObject is Row &&
				this.IsDropAllowed(this.Status.DragObject,
				 DesignerViewControl.MousePosition, DesignerViewControl.MouseButtons) ) {
				using ( Pen p = new Pen(Color.Black, 3.0F) ) {
					Row target = GetRowAt(DesignerViewControl.PointToClient(DesignerViewControl.MousePosition));
					try {
						if ( target != null ) {
							pe.Graphics.DrawLine(p, target.Bounds.X, target.Bounds.Y, target.Bounds.Right, target.Bounds.Y);
						} else if ( _rows.Count > 0 ) {
							target = _rows[_rows.Count - 1];
							pe.Graphics.DrawLine(p, target.Bounds.X, target.Bounds.Bottom, target.Bounds.Right, target.Bounds.Bottom);
						}
					} catch { }
				}
			}

			base.Paint(pe);
		}

		#endregion

		#endregion

		#region Protected Members

		#region Overrides

		protected override void OnSizeChanged(EventArgs e)
		{
			calculateScrollButtons();
			base.OnSizeChanged(e);
		}

		protected override void OnMouseLeave(EventArgs e)
		{
			this.Repaint();
			base.OnMouseLeave(e);
		}

		protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
		{
			if ( e.Button == System.Windows.Forms.MouseButtons.Left ||
				 e.Button == System.Windows.Forms.MouseButtons.Right ) {
				if ( RectangleToDesignerView(_rectUp).Contains(e.Location) && _iFirst > 0 ) {
					_iFirst--;
					Repaint();
				} else if ( RectangleToDesignerView(_rectDown).Contains(e.Location) &&
							_iFirst < this.Rows.Count - 1 ) {
					_iFirst++;
					Repaint();
				} else {
					bool itemselected = false;
					for ( int i = 0; i < this.Rows.Count; i++ ) {
						Rectangle rectRow = this.Rows[i].Bounds;
						if ( rectRow != Rectangle.Empty && rectRow.Contains(e.Location) ) {
							this.SelectedIndex = i;
							itemselected = true;
							break;
						}
					}
					if ( !itemselected )
						this.SelectedIndex = -1;
				}
			}
			base.OnMouseDown(e);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Right ) {
				if ( this.DesignerViewControl != null ) {
					if ( this.Status.DragObject != null ) {
						this.Repaint();
						//if ( !IsDropAllowed(this.Status.DragObject, e.Location, e.Button) ) {
						//    BitmapCursor defaultCursor = new BitmapCursor(Cursors.Default, new Bitmap(1, 1));
						//    this.DesignerViewControl.Status.UseCustomCursor = false;
						//    this.DesignerViewControl.Status.DragDropCursor = defaultCursor;
						//    this.DesignerViewControl.Cursor = Cursors.Default;
						//} else {
						//    BitmapCursor moveCursor = new BitmapCursor(Cursors.Default, new Bitmap(50, 50), DragDropEffects.Move);
						//    this.DesignerViewControl.Status.UseCustomCursor = true;
						//    this.DesignerViewControl.Status.DragDropCursor = moveCursor;
						//    this.DesignerViewControl.Cursor = moveCursor.Cursor;
						//}
					} else {
						Row dragObject = GetRowAt(e.Location);
						if ( dragObject != null && this.Status.DragObject == null ) {
							//this.DesignerViewControl.DoDragDrop(dragObject, DragDropEffects.Move);
							this.Status.DragObject = dragObject;
							this.DesignerViewControl.Status.UseCustomCursor = true;
							this.Status.CurrentMouseMoveMode = MouseMoveMode.DragDrop;
							try {
								BitmapCursor moveCursor = new BitmapCursor(Cursors.Default, new Bitmap(50, 50), DragDropEffects.Move);
								this.DesignerViewControl.Status.DragDropCursor = moveCursor;
								this.DesignerViewControl.Cursor = moveCursor.Cursor;
							} catch { }
						}
					}
				}
			}
			base.OnMouseMove(e);
		}

		public override void DropObject(object obj, Point location, MouseButtons button)
		{
			if ( button == MouseButtons.Right ) {
				Row targetRow = GetRowAt(location);
				Row sourceRow = obj as Row;
				if ( sourceRow != null ) {
					if ( targetRow != sourceRow ) {
						_rows.Remove(sourceRow);
						int pos = 0;
						if ( targetRow != null ) {
							pos = _rows.IndexOf(targetRow);
							_rows.Insert(pos, sourceRow);

						} else {
							pos = _rows.Count;
							_rows.Add(sourceRow);
						}
						EventHandler<FieldMoveEventArgs> tmp = new EventHandler<FieldMoveEventArgs>(FieldMoved);
						if ( tmp != null ) {
							tmp(this, new FieldMoveEventArgs(pos, sourceRow));
						}
					}
					this.Status.CurrentMouseMoveMode = MouseMoveMode.Normal;
					this.DesignerViewControl.Status.UseCustomCursor = false;
				}
			}
			base.DropObject(obj, location, button);
		}

		public override bool IsDropAllowed(object obj, Point location, MouseButtons button)
		{
			Row row = obj as Row;
			if ( row != null && row.ListView == this ) return true;
			return base.IsDropAllowed(obj, location, button);
		}

		public override bool IsDropAllowed(Type type, Point location, MouseButtons button)
		{
			if ( type == typeof(Row) ) return true;
			return base.IsDropAllowed(type, location, button);
		}

		protected override void OnMouseUp(MouseEventArgs e)
		{
			this.Status.DragObject = null;
			this.Status.CurrentMouseMoveMode = MouseMoveMode.Normal;
			this.DesignerViewControl.Status.UseCustomCursor = false;
			base.OnMouseUp(e);
		}

		protected override void OnMouseDoubleClick(System.Windows.Forms.MouseEventArgs e)
		{
			if ( e.Button == System.Windows.Forms.MouseButtons.Left ) {
				for ( int i = 0; i < this.Rows.Count; i++ ) {
					Rectangle rectRow = this.Rows[i].Bounds;
					if ( rectRow != Rectangle.Empty && rectRow.Contains(e.Location) ) {
						//int col;
						//Rectangle rect;
						break;
					}
				}
			}
			base.OnMouseDoubleClick(e);
		}

		#endregion

		#endregion

		#region Private Members

		#region Variables

		private bool _bShowHeader;

		private int _iSelected;
		private int _iFirst;
		private int _iRowHeight;
		private int _iHeaderHeight;
		private int _iScrollBtnHeight;

		private Rectangle _rectUp;
		private Rectangle _rectDown;

		private ColumnCollection _columns;
		private RowCollection _rows;

		private SolidBrush _brushHeaderFore;
		private SolidBrush _brushHeaderBack;
		private Pen _penBorder;
		private Pen _penSelectedRow;
		private StringFormat _format;

		//private System.Windows.Forms.TextBox _textBox;
		//private System.Windows.Forms.ComboBox _comboBox;

		#endregion

		#region Methods

		private void calculateScrollButtons()
		{
			int x = 0;
			int y = 0;
			int width = this.ClientRectangle.Width;
			int height = _iScrollBtnHeight;

			// set scroll up
			if ( this.ShowHeader )
				y = _iHeaderHeight;
			_rectUp = new Rectangle(x, y, width, height);

			// set scroll down
			y = this.ClientRectangle.Bottom - _iScrollBtnHeight;
			_rectDown = new Rectangle(x, y, width, height);
			
		}

		private void paintHeader(System.Windows.Forms.PaintEventArgs pe, List<int> columnWidths)
		{
			int pos = 0;
			for ( int i = 0; i < this.Columns.Count; i++ ) {
				Rectangle r = new Rectangle(pos, 0, columnWidths[i], _iHeaderHeight);
				Rectangle r2;
				pos = r.Width;
				r = this.RectangleToDesignerView(r);
				pe.Graphics.DrawRectangle(_penBorder, r);
				r.Inflate(-2, -2);
				r2 = r;
				r2.Width++;
				r2.Height++;
				pe.Graphics.FillRectangle(_brushHeaderBack, r2);
				pe.Graphics.DrawString(this.Columns[i].Name, this.Font, _brushHeaderFore, r, _format);
			}
		}
		private void paintScrollUpDown(System.Windows.Forms.PaintEventArgs pe)
		{
			Point p;
			// paint scroll up
			pe.Graphics.DrawRectangle(_penBorder, RectangleToDesignerView(_rectUp));
			p = new Point((int)( _rectUp.Width / 2 ) - ( Resources.bmp_scrollup_1.Width / 2 ), _rectUp.Top + 2);
			p = PointToDesignerView(p);
			if ( _iFirst == 0 )
				pe.Graphics.DrawImageUnscaled(Resources.bmp_scrollup_0, p);
			else
				pe.Graphics.DrawImageUnscaled(Resources.bmp_scrollup_1, p);
			// paint scroll down
			pe.Graphics.DrawRectangle(_penBorder, RectangleToDesignerView(_rectDown));
			p = new Point((int)( _rectDown.Width / 2 ) - ( Resources.bmp_scrolldown_1.Width / 2 ), _rectDown.Top + 2);
			p = PointToDesignerView(p);
			if ( this.Rows.Count == 0 || _iFirst == this.Rows.Count - 1 )
				pe.Graphics.DrawImageUnscaled(Resources.bmp_scrolldown_0, p);
			else
				pe.Graphics.DrawImageUnscaled(Resources.bmp_scrolldown_1, p);
		}
		private void paintRow(System.Windows.Forms.PaintEventArgs pe, Row row, int pos, List<int> columnWidths)
		{
			Rectangle r, bounds;
			int x, y, w, h;
			h = _iRowHeight;
			x = 0;
			y = pos * _iRowHeight + _iScrollBtnHeight;
			bounds = Rectangle.Empty;
			if ( this.ShowHeader )
				y += _iHeaderHeight;
			for ( int i = 0; i < columnWidths.Count; i++ ) {
				w = columnWidths[i];
				string str = "";
				if ( row.Count > i && row[i] != null )
					str = row[i].ToString();
				r = RectangleToDesignerView(new Rectangle(x, y, w, h));
				row.SetColumnRectangle(i, r);
				r.Inflate(-2, -2);
				if ( bounds == Rectangle.Empty )
					bounds = r;
				else
					bounds = Rectangle.Union(bounds, r);
				pe.Graphics.DrawString(str, this.Font, this.ForeBrush, r, _format);
				x += w;
			}
			bounds.Inflate(1, 1);
			if ( row.Selected ) {
				pe.Graphics.DrawRectangle(_penSelectedRow, bounds);
			}
			row.SetBounds(bounds);
			pe.Graphics.DrawLine(_penBorder, PointToDesignerView(new Point(0, y+h)),
											PointToDesignerView(new Point(this.ClientRectangle.Width, y+h)));
		}

		private void doShowHeaderChanged()
		{
			calculateScrollButtons();
			Refresh();
		}
		private void doSelectedIndexChanged()
		{
			for ( int i = 0; i < this.Rows.Count; i++ ) {
				this.Rows[i].SetSelected(i == _iSelected);
			}
			this.Repaint();
		}

		#endregion

		#region Event Handlers
		#endregion

		#endregion
	}

	public sealed class FieldMoveEventArgs : EventArgs
	{
		public FieldMoveEventArgs(int pos, object obj)
		{
			Position = pos;
			MovedObject = obj;
		}

		public object MovedObject { get; private set; }
		public int Position { get; private set; }
	}

	#region Class: Column
	public class Column
	{
		#region Initialization
		public Column()
		{
			_name = "";
			_type = ColumnType.TextBox;
			_width = -1;
			_fillWeight = 100;
		}
		public Column(string name) : this()
		{
			_name = name;
		}
		public Column(string name, ColumnType type) : this()
		{
			_name = name;
			_type = type;
		}
		public Column(string name, ColumnType type, int width) : this()
		{
			_name = name;
			_type = type;
			_width = width;
		}
		#endregion

		#region Properties

		private string _name;
		public string Name
		{
			get { return _name; }
			set { _name = value; }
		}

		private ColumnType _type;
		public ColumnType Type
		{
			get { return _type; }
			set { _type = value; }
		}

		private int _width;
		public int Width
		{
			get { return _width; }
			set { _width = value; }
		}

		private int _fillWeight;
		public int FillWeight
		{
			get { return _fillWeight; }
			set { _fillWeight = value; }
		}

		#endregion

		#region Methods
		#endregion

		#region Enum: ColumnType
		public enum ColumnType
		{
			TextBox,
			ComboBox
		}
		#endregion
	}
	#endregion
	#region Class: ColumnCollection
	public class ColumnCollection : CollectionBase
	{
		#region Initialization
		public ColumnCollection(ListView owner)
		{
			_owner = owner;
		}
		#endregion

		#region Indexer
		public Column this[int index]
		{
			get
			{
				return ( (Column)List[index] );
			}
			set
			{
				List[index] = value;
			}
		}
		#endregion

		#region Public Methods
		public int Add(Column value)
		{
			return ( List.Add(value) );
		}

		public int IndexOf(Column value)
		{
			return ( List.IndexOf(value) );
		}

		public void Insert(int index, Column value)
		{
			List.Insert(index, value);
		}

		public void Remove(Column value)
		{
			List.Remove(value);
		}

		public bool Contains(Column value)
		{
			// If value is not of type Column, this will return false.
			return ( List.Contains(value) );
		}
		public Column[] ToArray()
		{
			Column[] columns = new Column[InnerList.Count];
			Array.Copy(this.InnerList.ToArray(), 0, columns, 0, InnerList.Count);
			return columns;
		}
		#endregion

		#region Protected Overrides
		protected override void OnInsert(int index, Object value)
		{
			// TODO: Insert additional code to be run only when inserting values.
		}
		protected override void OnRemove(int index, Object value)
		{
			// TODO: Insert additional code to be run only when removing values.
		}
		protected override void OnSet(int index, Object oldValue, Object newValue)
		{
			// TODO: Insert additional code to be run only when setting values.
		}
		protected override void OnClear()
		{
			// TODO: Insert additional code to be run only when clearing list.
		}
		protected override void OnValidate(Object value)
		{
			if ( value.GetType() != typeof(Column) )
				throw new ArgumentException("value must be of type Column.", "value");
		}

		protected override void OnClearComplete()
		{
			refreshOwner();
			base.OnClearComplete();
		}
		protected override void OnInsertComplete(int index, object value)
		{
			refreshOwner();
			base.OnInsertComplete(index, value);
		}
		protected override void OnRemoveComplete(int index, object value)
		{
			refreshOwner();
			base.OnRemoveComplete(index, value);
		}
		protected override void OnSetComplete(int index, object oldValue, object newValue)
		{
			refreshOwner();
			base.OnSetComplete(index, oldValue, newValue);
		}
		#endregion

		#region Private Methods
		private void refreshOwner()
		{
			if ( _owner != null )
				_owner.Refresh();
		}
		#endregion
		#region Private Variables
		private ListView _owner;
		#endregion
	}
	#endregion

	#region Class: Row
	public class Row
	{
		#region Initialization
		internal Row()
		{
			_items = new ArrayList();
			_bounds = Rectangle.Empty;
			_bSelected = false;
			_dicColRects = new Dictionary<int, Rectangle>();
			_listView = null;
			_tag = null;
		}
		#endregion

		#region Properties
		public object this[int index]
		{
			get { return Items[index]; }
			set { Items[index] = value; }
		}
		public int Count
		{
			get { return Items.Count; }
		}
	
		private ArrayList _items;
		public ArrayList Items
		{
			get { return _items; }
			set { _items = value; }
		}

		private Rectangle _bounds;
		/// <summary>
		/// The Bounds of the Row in the coordinates of the MainPanel.
		/// </summary>
		public Rectangle Bounds
		{
			get
			{
				_listView.RecalculateRowBounds(
					this, _listView.Rows.IndexOf(this), _listView.CalculateColumnWidths());
				return _bounds;
			}
		}

		private bool _bSelected;
		public bool Selected
		{
			get { return _bSelected; }
		}

		private ListView _listView;
		public ListView ListView
		{
			get { return _listView; }
		}

		private object _tag;
		public object Tag
		{
			get { return _tag; }
			set { _tag = value; }
		}

		#endregion

		#region Methods
		internal bool GetColumnAtPoint(Point location, out int index, out Rectangle rect)
		{
			index = -1;
			rect = Rectangle.Empty;
			foreach ( KeyValuePair<int, Rectangle> kv in _dicColRects ) {
				if ( kv.Value.Contains(location) ) {
					index = kv.Key;
					rect = kv.Value;
					return true;
				}
			}
			return false;
		}

		public override string ToString()
		{
			if ( _items.Count == 0 ) return base.ToString();
			else if ( _items.Count == 1 ) return this._items[0].ToString();
			else if ( _items.Count == 2 ) return string.Format("{0} {1}", this._items[0], this._items[1]);
			else return base.ToString();
		}

		internal void SetListView(ListView listView)
		{
			_listView = listView;
		}

		internal void SetBounds(Rectangle bounds)
		{
			_bounds = bounds;
		}
		internal void SetSelected(bool selected)
		{
			_bSelected = selected;
		}
		internal void SetColumnRectangle(int iColumnIndex, Rectangle rect)
		{
			_dicColRects[iColumnIndex] = rect;
		}
		#endregion

		#region Variables
		private Dictionary<int, Rectangle> _dicColRects;
		#endregion
	}
	#endregion
	#region Class: RowCollection
	public class RowCollection : CollectionBase
	{
		#region Initialization
		public RowCollection(ListView owner)
		{
			_owner = owner;
		}
		#endregion

		#region Indexer
		public Row this[int index]
		{
			get
			{
				return ( (Row)List[index] );
			}
			set
			{
				List[index] = value;
			}
		}
		#endregion

		#region Public Methods
		public Row Add(params object[] values)
		{
			Row r = this.CreateNewRow();
			if ( values != null && values.Length > 0 )
				r.Items.AddRange(values);
			this.Add(r);
			return r;
		}
		public int Add(Row value)
		{
			value.SetListView(_owner);
			return ( List.Add(value) );
		}
		public int IndexOf(Row value)
		{
			return ( List.IndexOf(value) );
		}
		public void Insert(int index, Row value)
		{
			value.SetListView(_owner);
			List.Insert(index, value);
		}
		public void Remove(Row value)
		{
			if ( List.Contains(value) ) List.Remove(value);
		}
		public bool Contains(Row value)
		{
			// If value is not of type Row, this will return false.
			return ( List.Contains(value) );
		}
		public Row CreateNewRow()
		{
			Row r = new Row();
			r.SetListView(_owner);
			return r;
		}
		public Row[] ToArray()
		{
			Row[] rows = new Row[InnerList.Count];
			Array.Copy(InnerList.ToArray(), 0, rows, 0, InnerList.Count);
			return rows;
		}
		#endregion

		#region Protected Overrides
		protected override void OnInsert(int index, Object value)
		{
			// TODO: Insert additional code to be run only when inserting values.
		}
		protected override void OnRemove(int index, Object value)
		{
			// TODO: Insert additional code to be run only when removing values.
		}
		protected override void OnSet(int index, Object oldValue, Object newValue)
		{
			// TODO: Insert additional code to be run only when setting values.
		}
		protected override void OnClear()
		{
			// TODO: Insert additional code to be run only when clearing list.
		}
		protected override void OnValidate(Object value)
		{
			if ( value.GetType() != typeof(Row) )
				throw new ArgumentException("value must be of type Row.", "value");
		}

		protected override void OnClearComplete()
		{
			refreshOwner();
			base.OnClearComplete();
		}
		protected override void OnInsertComplete(int index, object value)
		{
			_owner.RecalculateRowBounds((Row)List[index], index, _owner.CalculateColumnWidths());
			refreshOwner();
			base.OnInsertComplete(index, value);
		}
		protected override void OnRemoveComplete(int index, object value)
		{
			refreshOwner();
			base.OnRemoveComplete(index, value);
		}
		protected override void OnSetComplete(int index, object oldValue, object newValue)
		{
			refreshOwner();
			base.OnSetComplete(index, oldValue, newValue);
		}
		#endregion

		#region Private Methods
		private void refreshOwner()
		{
			if ( _owner != null )
				_owner.Refresh();
		}
		#endregion
		#region Private Variables
		private ListView _owner;
		#endregion
	}
	#endregion

}
